/** @internal
 ** @file    imintegral.c
 ** @author  Brian Fulkerson
 ** @brief   Create an integral image - MEX definition
 **/

/* AUTORIGHTS
Copyright (C) 2007-10 Andrea Vedaldi and Brian Fulkerson

This file is part of VLFeat, available under the terms of the
GNU GPLv2, or (at your option) any later version.
*/

#include <mexutils.h>

#include <vl/generic.h>
#include <vl/imopv.h>

#include <stdlib.h>
#include <string.h>
#include <math.h>

void
mexFunction(int nout, mxArray *out[],
            int nin, const mxArray *in[])
{
  vl_size numDimensions, numChannels ;
  mwSize const *dimensions ;
  mxClassID classId ;
  void * integral ;
  void const * image ;
  vl_uindex k ;
  enum {IN_I=0} ;
  enum {OUT_J=0} ;

  /* -----------------------------------------------------------------
   *                                               Check the arguments
   * -------------------------------------------------------------- */

  if (nin > 1) {
    vlmxError(vlmxErrTooManyInputArguments, NULL) ;
  }
  if (nin < 1) {
    vlmxError(vlmxErrNotEnoughInputArguments, NULL) ;
  }
  if (nout > 1) {
    vlmxError(vlmxErrTooManyOutputArguments, NULL) ;
  }

  if (! mxIsNumeric(IN(I))) {
    vlmxError(vlmxErrInvalidArgument,
              "I is not numeric.") ;
  }

  dimensions = mxGetDimensions(IN(I)) ;
  numDimensions = mxGetNumberOfDimensions(IN(I)) ;
  if (numDimensions > 3) {
    vlmxError(vlmxErrInvalidArgument,
              "I has more than 3 dimensions (%d).", numDimensions) ;
  }
  if (numDimensions > 2) {
    numChannels = dimensions [2] ;
  } else {
    numChannels = 1 ;
  }

  classId = mxGetClassID(IN(I)) ;
  if (classId != mxSINGLE_CLASS &&
      classId != mxDOUBLE_CLASS &&
      classId != mxUINT32_CLASS &&
      classId != mxINT32_CLASS) {
    vlmxError(vlmxErrInvalidArgument,
              "I is not of a supported storage class.") ;
  }

  OUT(J) = mxCreateNumericArray(numDimensions, dimensions,
                                classId, mxREAL) ;

  image = mxGetData(IN(I)) ;
  integral = mxGetData(OUT(J)) ;

  /* -----------------------------------------------------------------
   *                                                        Do the job
   * -------------------------------------------------------------- */

#define DO(CLASS, T, SFX) \
case mx ## CLASS ## _CLASS : \
vl_imintegral_ ## SFX (integral, dimensions[0], \
  image, dimensions[0], dimensions[1], dimensions[0]) ; \
  integral = ((T *) integral) + dimensions[0]*dimensions[1] ; \
  image = ((T const *) image) + dimensions[0]*dimensions[1] ; \
break

  for (k = 0 ; k < numChannels ; ++k) {
    switch (classId) {
        DO(SINGLE, float, f) ;
        DO(DOUBLE, double, d) ;
        DO(UINT32, vl_uint32, ui32) ;
        DO(INT32, vl_int32, i32) ;
      default:
        abort() ;
    }
  }
}

